home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / DAN0411.ZIP / FISTBUG.ASM next >
Assembly Source File  |  1997-05-04  |  34KB  |  824 lines

  1.     page    60,132
  2. ;-----------------------------------------------------------------------------
  3. ;
  4. ; FISTBUG
  5. ;
  6. ;    Copyright (c) 1997-Present  Robert Collins
  7. ;
  8. ;       You have my permission to copy and distribute this software for
  9. ;       non-commercial purposes.  Any commercial use of this software or
  10. ;       source code is allowed, so long as the appropriate copyright
  11. ;       attributions (to me) are intact, *AND* my email address is properly
  12. ;       displayed.
  13. ;
  14. ;       Basically, give me credit, where credit is due, and show my email
  15. ;       address.
  16. ;
  17. ;-----------------------------------------------------------------------------
  18. ;
  19. ;       Robert R. Collins               email:  rcollins@x86.org
  20. ;
  21. ;-----------------------------------------------------------------------------
  22. ;
  23. ; FISTBUG --
  24. ;
  25. ; If all you're interested in seeing is the source code which should be
  26. ; offered for academic and peer review, please refer to the subrutines
  27. ; 'FistTest16' and 'FistTest32.'
  28. ;
  29. ; Synopsis:
  30. ; This program tests for a bug in the Pentium Pro and Pentium II floating
  31. ; point unit.  This program may be run on a variety of microprocessors
  32. ; from the 80286 on up.  For a complete description of the bug, please refer
  33. ; to http://www.x86.org/secrets/Dan0411.html.
  34. ;
  35. ; To assemble this source code:
  36. ; * You will need Microsoft Macro Assembler, version 6.11d (though just about
  37. ;   any other version of MASM will probably work).  Borland TASM will probably
  38. ;   work also.
  39. ; * Run the makefile using the 'nmake' utility supplied with MASM.
  40. ; * You may compile this without the nmake utility by invoking the command
  41. ;   line:
  42. ;   C: > ml /Fl fistbug.asm        - to generate non-verbose version
  43. ;   C: > ml /Fl /DVERBOSE fistbug.asm    - to genrate verbose version
  44. ;
  45. ;-----------------------------------------------------------------------------
  46.  
  47.  
  48. ;-----------------------------------------------------------------------------
  49. ; Assembler directives
  50. ;-----------------------------------------------------------------------------
  51.     .xlist            ; disable list file
  52.     .286
  53.  
  54. ;-----------------------------------------------------------------------------
  55. ; Include file section
  56. ;-----------------------------------------------------------------------------
  57.  
  58. ;-----------------------------------------------------------------------------
  59. ; Equates
  60. ;-----------------------------------------------------------------------------
  61.     FSW_IE    equ    1        ; Status Word IE bit
  62.  
  63. ;-----------------------------------------------------------------------------
  64. ; Macros
  65. ;-----------------------------------------------------------------------------
  66. PRINT_PASS_FAIL MACRO
  67. ifdef    VERBOSE
  68.     pushf                ; save results of comparison
  69.     mov    ah,9            ; print string function ID
  70.     mov    dx,offset PassMsg    ; prepare for test passed
  71.     jnz    @F            ; test did pass
  72.     mov    dx,offset FailMsg    ; get address of failed message
  73. @@:    int    21h            ; print message
  74.     popf                ; restore flags
  75. endif                    ; VERBOSE
  76. ENDM
  77.  
  78.  
  79. PRINT_MSG    MACRO    MSG
  80. ifdef    VERBOSE
  81.     mov    ah,9
  82.     mov    dx,offset MSG
  83.     int    21h
  84. endif                    ; VERBOSE
  85. ENDM
  86.  
  87.  
  88. ;-----------------------------------------------------------------------------
  89. ; 16-bit Floating point environment
  90. ;
  91. ; I intentionally chose a 16-bit floating point environment to allow this
  92. ; program to be run on the 80286 microprocessor.
  93. ;-----------------------------------------------------------------------------
  94.     FPU_Struct    STRUCT
  95.     FCW        dw    ?    ; Control word
  96.     FSW        dw    ?    ; Status word
  97.     FTW        dw    ?    ; Tag word
  98.             dw    ?    ; Floating point IP
  99.             dw    ?    ; Floating point CS
  100.             dw    ?    ; Operand offset
  101.             dw    ?    ; Operand selector
  102.     ST0        dt    ?    ; ST0
  103.     ST1        dt    ?    ; ST1
  104.     ST2        dt    ?    ; ST2
  105.     ST3        dt    ?    ; ST3
  106.     ST4        dt    ?    ; ST4
  107.     ST5        dt    ?    ; ST5
  108.     ST6        dt    ?    ; ST6
  109.     ST7        dt    ?    ; ST7
  110.     FPU_Struct    ENDS
  111.  
  112.  
  113.     .list
  114. ;-----------------------------------------------------------------------------
  115. ; Dummy segments
  116. ;-----------------------------------------------------------------------------
  117.     INTSEG    segment at 0
  118.  
  119.     org    6*4
  120.     INT06        dd    ?
  121.         INTSEG  ends
  122.  
  123.  
  124. ;-----------------------------------------------------------------------------
  125. ; Data segment
  126. ;-----------------------------------------------------------------------------
  127.     _DATA segment use16 para public 'DATA'
  128.  
  129. ;-----------------------------------------------------------------------------
  130. ; Instantiate the floating point environment structure.  I might as well make
  131. ; this appear at the paragraph boundary of the data segment.
  132. ;-----------------------------------------------------------------------------
  133.     FENV    FPU_Struct    <>
  134.  
  135. ;-----------------------------------------------------------------------------
  136. ; This is where the list of floating point numbers is stored.  If you want
  137. ; to add to this list, simply insert a floating point number in the 16-bit
  138. ; section, or the 32-bit section, depending on what your needs are.  For
  139. ; example, you may want to verify that positive numbers aren't affected by
  140. ; this bug.  To do so, you could simply insert a line such as:
  141. ;    dt    65536.0
  142. ; The operand doesn't need to be given in hex as my examples were.  My
  143. ; examples were choosen in hex to easily demonstrate the boundary conditions
  144. ; of the Dan-0411 bug.
  145. ;
  146. ; If you insert new operands, you don't need to make any other program
  147. ; changes, but you will need to reassemble the source code.  The program
  148. ; automatically adjust the nuber of test cases according to how many
  149. ; operands appear in the Op16 or Op32 list.
  150. ;-----------------------------------------------------------------------------
  151.     Op16        dt    0c06e8000000000000001h
  152.             dt    0c06e8000000000000010h
  153.             dt    0c06e8000000000000100h
  154.             dt    0c06e8000000000001000h
  155.             dt    0c06e8000000000010000h
  156.             dt    0c06e8000000000100000h
  157.             dt    0c06e8000000001000000h
  158.             dt    0c06e8000000010000000h
  159.             dt    0c06e8000000100000000h
  160.             dt    0c06e8000001000000000h
  161.             dt    0c06e8000010000000000h
  162.             dt    0c06e8000100000000000h
  163.             dt    0c06e80007fffffffffffh
  164.         N16             equ     ($-Op16) / sizeof Op16
  165.  
  166.         Op32            dt      0c05e8000000000000001h
  167.             dt    0c05e8000000000000010h
  168.             dt    0c05e8000000000000100h
  169.             dt    0c05e8000000000001000h
  170.             dt    0c05e8000000000010000h
  171.             dt    0c05e8000000000100000h
  172.             dt    0c05e8000000001000000h
  173.             dt    0c05e8000000010000000h
  174.             dt    0c05e800000007fffffffh
  175.         N32             equ     ($-Op32) / sizeof Op32
  176.  
  177. ;-----------------------------------------------------------------------------
  178. ; D16 and D32 listed below are the destinations for the FIST and FISTP
  179. ; (Floating-to-Integer Store) instructions.  The StatusWord variable is used
  180. ; to collect the resultant status words for the four different test cases on
  181. ; each floating point operand.    'Results' is used to accumulate the results.
  182. ; At the end of this test, if any bit is set in 'Results' then the test is
  183. ; considered a failure, and you've got the Dan-0411 bug.
  184. ;-----------------------------------------------------------------------------
  185.         D16             dw      55aah
  186.         D32             dd      55aa55aah
  187.     StatusWord    dw    4 dup (0)
  188.     Results     dw    0    ; Cumulative results
  189.  
  190.  
  191. ;-----------------------------------------------------------------------------
  192. ; Misc data storage.
  193. ;-----------------------------------------------------------------------------
  194.     CPUIDVal    dd    0    ; Results of CPUID instruction
  195.     OrigINT06    dd    0    ; Temp holding spot for INT06 vector
  196.  
  197.  
  198. ;-----------------------------------------------------------------------------
  199. ; String messages used for formatting the screen output
  200. ;-----------------------------------------------------------------------------
  201. ;   16-bit Value       FLD/FIST    FRSTOR/FIST    FLD/FISTP   FRSTOR/FISTP
  202. ; xxxxxxxxxxxxxxxxxx     PASS          PASS      PASS           PASS
  203.     HeaderMsg16    db    "    16-bit Value       FLD/FIST    FRSTOR/FIST  FLD/FISTP   FRSTOR/FISTP",0dh,0ah,24h
  204.     HeaderMsg32    db    "    32-bit Value       FLD/FIST    FRSTOR/FIST  FLD/FISTP   FRSTOR/FISTP",0dh,0ah,24h
  205.     ValueBuf    db    "                       ",24h
  206.     Spaces        db    "     ",24h
  207.     PassMsg     db    "  PASS  ",24h
  208.     FailMsg     db    "**FAIL**",24h
  209.     CRLFMsg     db    0dh,0ah,24h
  210.  
  211.     PMMsg        db    "Running in protected mode (probably Windows).  Results are most",0dh,0ah
  212.             db    "reliable while running in real mode (booting clean to DOS).",0dh,0ah
  213.             db    "I'll try running anyways.",0dh,0ah,24h
  214.  
  215.     CPUIDMsg    db    "Microprocessor ID:  "
  216.     FamilyString    db    "Unknown "
  217.             db    "  Vendor String:  "
  218.     IDString    db    "Not Detected",0dh,0ah,24h
  219.  
  220.     Dan0411Failed    db    "*** Dan-0411 bug found. ***",0dh,0ah,24h
  221.     Dan0411Passed    db    "Dan-0411 not found.",0dh,0ah,24h
  222.     _DATA    ENDS
  223.  
  224.  
  225. ;-----------------------------------------------------------------------------
  226. ; Beginning of main code segment
  227. ;-----------------------------------------------------------------------------
  228.     _TEXT    segment para public use16 'CODE'
  229.     ASSUME    CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
  230. ;-----------------------------------------------------------------------------
  231. ; Code starts here
  232. ; * Set up stack
  233. ;-----------------------------------------------------------------------------
  234.     FISTBUG     proc    far
  235.     mov    ax,seg STACK        ; setup stack segment
  236.     mov    ss,ax
  237.     mov    sp,sizeof StackPtr
  238.     xor    ax,ax            ; clear it
  239.     pushf
  240.     push    ds            ; save far return on stack
  241.     push    ax
  242.  
  243. ;-----------------------------------------------------------------------------
  244. ; * Disable interrupts during this test
  245. ; * Set up data segments
  246. ;-----------------------------------------------------------------------------
  247.     cli                ; disable interrupts
  248.     mov    ax,seg _DATA        ; get data segment
  249.     mov    ds,ax
  250.     mov    es,ax
  251.  
  252. ifdef  VERBOSE
  253. ;-----------------------------------------------------------------------------
  254. ; The purpoase of this section of code is to determine a few things about
  255. ; the target computer.    I'll detect whether or not we're in protected mode
  256. ; (like running in a DOS-box of Windows) and print a message accordingly.
  257. ; Whether or not we're in protected mode shouldn't make any difference, as
  258. ; I'm not executing any priviledged instryctions.
  259. ;
  260. ; Also in this section, I check for the processor stepping information and
  261. ; vendor string.  If present, I'll print this information to the screen.
  262. ;-----------------------------------------------------------------------------
  263. ; Test for protected mode
  264. ;-----------------------------------------------------------------------------
  265.     smsw    ax            ; get lower bits of CR0
  266.     test    al,1            ; in protected mode?
  267.     jz    @F            ; nope
  268.     PRINT_MSG    PMMsg        ; print protected mode message
  269.     PRINT_MSG    CRLFMsg     ; print <CRLF>
  270.  
  271. ;-----------------------------------------------------------------------------
  272. ; Install INT06 (Invalid opcode) exception handler
  273. ;-----------------------------------------------------------------------------
  274. @@:    push    es            ; save
  275.     mov    ax,seg INTSEG
  276.     mov    es,ax
  277.     mov    ax,offset OurINT6    ; get pointer to our INT6 handler
  278.     mov    dx,cs            ; get our code segment
  279.     xchg    ax,word ptr es:INT06    ; swap 'em
  280.     xchg    dx,word ptr es:INT06[2] ; swap vector
  281.     mov    word ptr OrigINT06,ax    ; save original vector
  282.     mov    word ptr OrigINT06[2],dx; vector now saved
  283.     pop    es            ; restore original segment
  284.  
  285. ;-----------------------------------------------------------------------------
  286. ; Execute CPUID instruction and print results on string
  287. ;
  288. ; This is a real down-and-dirty way to detect CPUID.  I've installed an
  289. ; invalid exception handler, and pointed DX to a return address in the case
  290. ; that an invalid opcode exception occurs.  If we're an 80286, then the
  291. ; 'xor eax,eax' instruction will cause the invalid opcode fault.  If we're
  292. ; running on a processor that doesn't support CPUID, the 'cpuid' instruction
  293. ; will cause the invalid opcode fault.    In either case, if the fault occurs,
  294. ; execution continues beyond the processor detection code.  At that point,
  295. ; the processor stepping information is printed anyways with a default
  296. ; response.  If CPUID does work, then the default results are filled in with
  297. ; the appropriate CPUID return values.
  298. ;-----------------------------------------------------------------------------
  299. .586
  300.     mov    dx,offset @NoCPUID    ; set destination location
  301.     xor    eax,eax         ; real dirty way to detect 80386+
  302.     cpuid                ; try CPUID instruction
  303.     mov    dword ptr IDString[0],ebx
  304.     mov    dword ptr IDString[4],edx
  305.     mov    dword ptr IDString[8],ecx
  306.     mov    eax,1            ; do next level of CPUID
  307.     cpuid                ; get processor stepping
  308.     mov    CPUIDVal,eax        ; save it
  309.     mov    si,offset CPUIDVal    ; get source of CPUID stepping
  310.     mov    di,offset FamilyString    ; get destination of string
  311.     mov    cx,4            ; # of bytes to convert
  312.     call    hex_string        ; convert data
  313.  
  314. @NoCPUID:
  315. .286
  316.     PRINT_MSG    CPUIDMsg    ; print CPUID message
  317.     PRINT_MSG    CRLFMsg     ; print <CRLF>
  318.  
  319. ;-----------------------------------------------------------------------------
  320. ; Restore invalid opcode interrupt handler
  321. ;-----------------------------------------------------------------------------
  322.     push    es            ; save
  323.     mov    ax,seg INTSEG
  324.     mov    es,ax
  325.     mov    ax,word ptr OrigINT06[0]; get pointer to our INT6 handler
  326.     mov    dx,word ptr OrigINT06[2]; get our code segment
  327.     xchg    ax,word ptr es:INT06    ; swap 'em
  328.     xchg    dx,word ptr es:INT06[2] ; swap vector
  329.     pop    es            ; restore original segment
  330.  
  331. ;-----------------------------------------------------------------------------
  332. ; Print header message
  333. ;-----------------------------------------------------------------------------
  334.     PRINT_MSG    HeaderMsg16    ; print beginning header message
  335. endif
  336.  
  337. ;-----------------------------------------------------------------------------
  338. ; Time to start test
  339. ;-----------------------------------------------------------------------------
  340.     mov    cx,N16            ; # of 16-bit operands to test
  341.     xor    si,si            ; Initialize index pointer to operands
  342.  
  343. @FistLoop16:
  344.  
  345. ifdef VERBOSE
  346. ;-----------------------------------------------------------------------------
  347. ; The purpose of this section is printing the 80-bit hex operands to the
  348. ; screen.  Each 80-bit operand is converted to ASCII and printed on the
  349. ; screen.
  350. ;-----------------------------------------------------------------------------
  351.     push    cx
  352.     push    si
  353.  
  354. ;-----------------------------------------------------------------------------
  355. ; * Convert data to ASCII
  356. ; * Print value on screen
  357. ;-----------------------------------------------------------------------------
  358.     lea    si,Op16[si]        ; get pointer to data
  359.     mov    di,offset ValueBuf    ; get output buffer
  360.     mov    cx,sizeof Op16        ; get # of bytes to convert
  361.     call    hex_string
  362.     PRINT_MSG    ValueBuf    ; print 10-byte hex value on screen
  363.     pop    si
  364.     pop    cx
  365. endif                    ; VERBOSE
  366.  
  367.  
  368. ;-----------------------------------------------------------------------------
  369. ; Start test
  370. ;-----------------------------------------------------------------------------
  371.     call    FistTest16        ; Check various form of executing
  372.                     ;  FIST[P] and saving FSW
  373.  
  374. ;-----------------------------------------------------------------------------
  375. ; This section tests for the results of each of the operand test cases.
  376. ; Each test case is checked for the FSW.IE flag set.  A pass/fail message is
  377. ; printed if running in VERBOSE mode.  Otherwise, results are collected in
  378. ; the 'Results' variable for processing at the end of the test.
  379. ;-----------------------------------------------------------------------------
  380. ; Check for results
  381. ;-----------------------------------------------------------------------------
  382.     push    cx            ; save current count
  383.     xor    di,di
  384.     mov    cx,4            ; # of results to check
  385.  
  386. ;-----------------------------------------------------------------------------
  387. ; Check for FSW.IE.  If set, indicate results.    If VERBOSE, print to the
  388. ; screen (macros handle verbose mode printing).  Iterate through each test
  389. ; case until finished.
  390. ;-----------------------------------------------------------------------------
  391. Check16:
  392.     test    StatusWord[di],FSW_IE    ; check for correct exception
  393.     PRINT_PASS_FAIL
  394.     jnz    @F            ; yes, behavior correct
  395.     or    Results,-1        ; set results to indicate failure
  396. @@:    add    di,2            ; point to next datum
  397.     dec    cx            ; are we done yet?
  398.     jz    @F            ; yes
  399.     PRINT_MSG    Spaces
  400.     jmp    Check16
  401.  
  402. @@:    PRINT_MSG    CRLFMsg     ; print <CRLF>
  403.     pop    cx
  404.     add    si,sizeof Op16
  405.     loop    @FistLoop16
  406.  
  407. ;-----------------------------------------------------------------------------
  408. ; Now done testing all 16-bit operands.
  409. ; Time to test 32-bit operands.
  410. ;-----------------------------------------------------------------------------
  411. ; Print header message
  412. ;-----------------------------------------------------------------------------
  413.     PRINT_MSG    CRLFMsg     ; print <CRLF>
  414.     PRINT_MSG    HeaderMsg32    ; print header message for 32-bit test
  415.  
  416. ;-----------------------------------------------------------------------------
  417. ; Put code here...
  418. ;-----------------------------------------------------------------------------
  419.     mov    cx,N32            ; # of 32-bit operands to test
  420.     xor    si,si            ; Initialize index pointer to operands
  421.  
  422. @FistLoop32:
  423.  
  424. ifdef    VERBOSE
  425. ;-----------------------------------------------------------------------------
  426. ; The purpose of this section is printing the 80-bit hex operands to the
  427. ; screen.  Each 80-bit operand is converted to ASCII and printed on the
  428. ; screen.
  429. ;-----------------------------------------------------------------------------
  430.     push    cx
  431.     push    si
  432.  
  433. ;-----------------------------------------------------------------------------
  434. ; * Convert data to ASCII
  435. ; * Print value on screen
  436. ;-----------------------------------------------------------------------------
  437.     lea    si,Op32[si]        ; get pointer to data
  438.     mov    di,offset ValueBuf    ; get output buffer
  439.     mov    cx,sizeof Op32        ; get # of bytes to convert
  440.     call    hex_string
  441.     PRINT_MSG    ValueBuf    ; print 10-byte data on screen
  442.     pop    si
  443.     pop    cx
  444. endif                    ; VERBOSE
  445.  
  446. ;-----------------------------------------------------------------------------
  447. ; Start test
  448. ;-----------------------------------------------------------------------------
  449.     call    FistTest32        ; Check various form of executing
  450.                     ;  FIST[P] and saving FSW
  451.  
  452. ;-----------------------------------------------------------------------------
  453. ; This section tests for the results of each of the operand test cases.
  454. ; Each test case is checked for the FSW.IE flag set.  A pass/fail message is
  455. ; printed if running in VERBOSE mode.  Otherwise, results are collected in
  456. ; the 'Results' variable for processing at the end of the test.
  457. ;-----------------------------------------------------------------------------
  458. ; Check for results
  459. ;-----------------------------------------------------------------------------
  460.     push    cx            ; save current count
  461.     xor    di,di
  462.     mov    cx,4            ; # of results to check
  463.  
  464. ;-----------------------------------------------------------------------------
  465. ; Check for FSW.IE.  If set, indicate results.    If VERBOSE, print to the
  466. ; screen (macros handle verbose mode printing).  Iterate through each test
  467. ; case until finished.
  468. ;-----------------------------------------------------------------------------
  469. Check32:
  470.     test    StatusWord[di],FSW_IE    ; check for correct exception
  471.     PRINT_PASS_FAIL
  472.     jnz    @F            ; yes, behavior correct
  473.     or    Results,-1        ; set results to indicate failure
  474. @@:    add    di,2            ; point to next datum
  475.     dec    cx            ; are we done yet?
  476.     jz    @F            ; yes
  477.     PRINT_MSG    Spaces
  478.     jmp    Check32
  479.  
  480. @@:    PRINT_MSG    CRLFMsg     ; print <CRLF>
  481.     pop    cx
  482.     add    si,sizeof Op32
  483.     loop    @FistLoop32
  484.  
  485. ;-----------------------------------------------------------------------------
  486. ; Now done testing all 32-bit operands.
  487. ; Now let's print the final results of the test.  Does your processor have
  488. ; the 'Dan-0411' bug?  If so, the results are printed here.
  489. ;-----------------------------------------------------------------------------
  490.     mov    ah,9            ; get function to print string
  491.     mov    dx,offset CRLFMsg    ; get pointer to CRLF message
  492.     int    21h
  493.     mov    dx,offset Dan0411Passed ; prepare to pass
  494.     test    Results,-1        ; anything fail?
  495.     jz    @F            ; nope
  496.     mov    dx,offset Dan0411Failed ; get failed message
  497. @@:    int    21h
  498.  
  499. ;-----------------------------------------------------------------------------
  500. ; Terminate and return to DOS.
  501. ;-----------------------------------------------------------------------------
  502.     iret                ; return to DOS
  503. FISTBUG     endp
  504.  
  505.  
  506. ;-----------------------------------------------------------------------------
  507.   FistTest16    proc    near
  508. ;-----------------------------------------------------------------------------
  509. ; FistTest16 checks four different ways of executing the FIST[P] instruction
  510. ; and storing the status word to memory.  Before each sub-test is attempted,
  511. ; the floating point unit is re-initialized with the fninit instruction.
  512. ; The FPU re-initialization ensures that any pending ("sticky") floating point
  513. ; errors from the previous test will be cleared.  This also guarantees that
  514. ; the each sub-tests is performed on a pristine FPU environment.
  515. ;
  516. ; The four test cases are as follows:
  517. ; 1) * Floating point load using  FLD     instruction
  518. ;    * Floating point store using FIST     instruction
  519. ;    * Store status word using      FNSTSW instruction.
  520. ;
  521. ; 2) * Floating point load using  FLD     instruction
  522. ;    * Save floating point environment with FNSAVE instruction.  This
  523. ;      instruction has the side-effect of re-initializing the FPU state (a
  524. ;      good thing).
  525. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  526. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  527. ;    * Floating point store using FIST     instruction
  528. ;    * Store status word using      FNSTSW instruction.
  529. ;
  530. ; 3) * Floating point load using  FLD     instruction
  531. ;    * Floating point store using FISTP  instruction
  532. ;    * Store status word using      FNSTSW instruction.
  533. ;
  534. ; 4) * Floating point load using  FLD     instruction
  535. ;    * Save floating point environment with FNSAVE instruction.  This
  536. ;      instruction has the side-effect of re-initializing the FPU state (a
  537. ;      good thing).
  538. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  539. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  540. ;    * Floating point store using FISTP  instruction
  541. ;    * Store status word using      FNSTSW instruction.
  542. ;
  543. ;-----------------------------------------------------------------------------
  544. ; Input:   DS:SI = Index pointer to 80-bit floating point operand
  545. ; Output:  StatusWord filled in with FPU status words for each test case.
  546. ;-----------------------------------------------------------------------------
  547. ; Restore pristine environment.
  548. ;-----------------------------------------------------------------------------
  549.     xor    di,di            ; initialize pointer to results
  550.     fninit                ; initialize floating point unit
  551.  
  552. ;-----------------------------------------------------------------------------
  553. ; 1) * Floating point load using  FLD     instruction
  554. ;    * Floating point store using FIST     instruction
  555. ;    * Store status word using      FNSTSW instruction.
  556. ;-----------------------------------------------------------------------------
  557.     fld    Op16[si]        ; load a value
  558.     fist    D16
  559.     fnstsw    StatusWord[di]        ; save results
  560.  
  561. ;-----------------------------------------------------------------------------
  562. ; Restore pristine environment.
  563. ;-----------------------------------------------------------------------------
  564.     add    di,2            ; point to next FSW results datum
  565.     fninit                ; initialize floating point unit
  566.  
  567. ;-----------------------------------------------------------------------------
  568. ; 2) * Floating point load using  FLD     instruction
  569. ;    * Save floating point environment with FNSAVE instruction.  This
  570. ;      instruction has the side-effect of re-initializing the FPU state (a
  571. ;      good thing).
  572. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  573. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  574. ;    * Floating point store using FIST     instruction
  575. ;    * Store status word using      FNSTSW instruction.
  576. ;-----------------------------------------------------------------------------
  577.     fld    Op16[si]        ; load a value
  578.     fnsave    FENV            ; save a copy of environment
  579.                     ;  does implicit fninit
  580.     frstor    FENV            ; restore FPU environment
  581.     fist    D16
  582.     fnstsw    StatusWord[di]        ; save results
  583.  
  584. ;-----------------------------------------------------------------------------
  585. ; Restore pristine environment.
  586. ;-----------------------------------------------------------------------------
  587.     add    di,2            ; point to next data value
  588.     fninit                ; initialize floating point unit
  589.  
  590. ;-----------------------------------------------------------------------------
  591. ; 3) * Floating point load using  FLD     instruction
  592. ;    * Floating point store using FISTP  instruction
  593. ;    * Store status word using      FNSTSW instruction.
  594. ;
  595. ;-----------------------------------------------------------------------------
  596.     fld    Op16[si]        ; load a value
  597.     fistp    D16
  598.     fnstsw    StatusWord[di]        ; save results
  599.  
  600. ;-----------------------------------------------------------------------------
  601. ; Restore pristine environment.
  602. ;-----------------------------------------------------------------------------
  603.     add    di,2            ; point to next data value
  604.     fninit                ; initialize floating point unit
  605.  
  606. ;-----------------------------------------------------------------------------
  607. ; 4) * Floating point load using  FLD     instruction
  608. ;    * Save floating point environment with FNSAVE instruction.  This
  609. ;      instruction has the side-effect of re-initializing the FPU state (a
  610. ;      good thing).
  611. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  612. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  613. ;    * Floating point store using FISTP  instruction
  614. ;    * Store status word using      FNSTSW instruction.
  615. ;-----------------------------------------------------------------------------
  616.     fld    Op16[si]        ; load a value
  617.     fnsave    FENV            ; save a copy of environment
  618.                     ;  does implicit fninit
  619.     frstor    FENV            ; restore FPU environment
  620.     fistp    D16
  621.     fnstsw    StatusWord[di]        ; save results
  622.     ret
  623. FistTest16    endp
  624.  
  625.  
  626. ;-----------------------------------------------------------------------------
  627.   FistTest32    proc    near
  628. ;-----------------------------------------------------------------------------
  629. ;
  630. ; FistTest32 checks four different ways of executing the FIST[P] instruction
  631. ; and storing the status word to memory.  Before each sub-test is attempted,
  632. ; the floating point unit is re-initialized with the fninit instruction.
  633. ; The FPU re-initialization ensures that any pending ("sticky") floating point
  634. ; errors from the previous test will be cleared.  This also guarantees that
  635. ; the each sub-tests is performed on a pristine FPU environment.
  636. ;
  637. ; The four test cases are as follows:
  638. ; 1) * Floating point load using  FLD     instruction
  639. ;    * Floating point store using FIST     instruction
  640. ;    * Store status word using      FNSTSW instruction.
  641. ;
  642. ; 2) * Floating point load using  FLD     instruction
  643. ;    * Save floating point environment with FNSAVE instruction.  This
  644. ;      instruction has the side-effect of re-initializing the FPU state (a
  645. ;      good thing).
  646. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  647. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  648. ;    * Floating point store using FIST     instruction
  649. ;    * Store status word using      FNSTSW instruction.
  650. ;
  651. ; 3) * Floating point load using  FLD     instruction
  652. ;    * Floating point store using FISTP  instruction
  653. ;    * Store status word using      FNSTSW instruction.
  654. ;
  655. ; 4) * Floating point load using  FLD     instruction
  656. ;    * Save floating point environment with FNSAVE instruction.  This
  657. ;      instruction has the side-effect of re-initializing the FPU state (a
  658. ;      good thing).
  659. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  660. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  661. ;    * Floating point store using FISTP  instruction
  662. ;    * Store status word using      FNSTSW instruction.
  663. ;
  664. ;-----------------------------------------------------------------------------
  665. ; Input:   DS:SI = Index pointer to 80-bit floating point operand
  666. ; Output:  StatusWord filled in with FPU status words for each test case.
  667. ;-----------------------------------------------------------------------------
  668. ; Restore pristine environment.
  669. ;-----------------------------------------------------------------------------
  670.     xor    di,di            ; initialize pointer to results
  671.     fninit                ; initialize floating point unit
  672.  
  673. ;-----------------------------------------------------------------------------
  674. ; 1) * Floating point load using  FLD     instruction
  675. ;    * Floating point store using FIST     instruction
  676. ;    * Store status word using      FNSTSW instruction.
  677. ;-----------------------------------------------------------------------------
  678.     fld    Op32[si]        ; load a value
  679.     fist    D32
  680.     fnstsw    StatusWord[di]        ; save results
  681.  
  682. ;-----------------------------------------------------------------------------
  683. ; Restore pristine environment.
  684. ;-----------------------------------------------------------------------------
  685.     add    di,2            ; point to next data value
  686.     fninit                ; initialize floating point unit
  687.  
  688. ;-----------------------------------------------------------------------------
  689. ; 2) * Floating point load using  FLD     instruction
  690. ;    * Save floating point environment with FNSAVE instruction.  This
  691. ;      instruction has the side-effect of re-initializing the FPU state (a
  692. ;      good thing).
  693. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  694. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  695. ;    * Floating point store using FIST     instruction
  696. ;    * Store status word using      FNSTSW instruction.
  697. ;-----------------------------------------------------------------------------
  698.     fld    Op32[si]        ; load a value
  699.     fnsave    FENV            ; save a copy of environment
  700.                     ;  does implicit fninit
  701.     frstor    FENV            ; restore FPU environment
  702.     fist    D32
  703.     fnstsw    StatusWord[di]        ; save results
  704.  
  705. ;-----------------------------------------------------------------------------
  706. ; Restore pristine environment.
  707. ;-----------------------------------------------------------------------------
  708.     add    di,2            ; point to next data value
  709.     fninit                ; initialize floating point unit
  710.  
  711. ;-----------------------------------------------------------------------------
  712. ; 3) * Floating point load using  FLD     instruction
  713. ;    * Floating point store using FISTP  instruction
  714. ;    * Store status word using      FNSTSW instruction.
  715. ;
  716. ;-----------------------------------------------------------------------------
  717.     fld    Op32[si]        ; load a value
  718.     fistp    D32
  719.     fnstsw    StatusWord[di]        ; save results
  720.  
  721. ;-----------------------------------------------------------------------------
  722. ; Restore pristine environment.
  723. ;-----------------------------------------------------------------------------
  724.     add    di,2            ; point to next data value
  725.     fninit                ; initialize floating point unit
  726.  
  727. ;-----------------------------------------------------------------------------
  728. ; 4) * Floating point load using  FLD     instruction
  729. ;    * Save floating point environment with FNSAVE instruction.  This
  730. ;      instruction has the side-effect of re-initializing the FPU state (a
  731. ;      good thing).
  732. ;    * Restore the FPU state with FRSTOR instruction.  This ensures that
  733. ;      the Dan-0411 error wasn't a byproduct of the FLD instruction.
  734. ;    * Floating point store using FISTP  instruction
  735. ;    * Store status word using      FNSTSW instruction.
  736. ;-----------------------------------------------------------------------------
  737.     fld    Op32[si]        ; load a value
  738.     fnsave    FENV            ; save a copy of environment
  739.                     ;  does implicit fninit
  740.     frstor    FENV            ; restore FPU environment
  741.     fistp    D32
  742.     fnstsw    StatusWord[di]        ; save results
  743.     ret
  744. FistTest32    endp
  745.  
  746.  
  747. ;-----------------------------------------------------------------------------
  748. ; HEX_STRING:    Convert a string of 8-bit hex numbers to ASCII.
  749. ; Input:   DS:SI = Pointer to hex data
  750. ;       ES:DI = Buffer to get output
  751. ;       CX     = # of bytes to convert
  752. ; Output:  ES:DI = Filled in w/ ASCII hex#
  753. ;-----------------------------------------------------------------------------
  754.   Hex_String    proc    near
  755. ;-----------------------------------------------------------------------------
  756.     jcxz    @Hex_str_exit        ; go split
  757.     push    ax            ; [bp][0ah]
  758.     push    cx            ; [bp][8]
  759.     push    dx            ; [bp][6]
  760.     push    si            ; [bp][4]
  761.     push    di            ; [bp][2]
  762.     push    bp            ; [bp]
  763.     mov    bp,sp
  764.     add    si,cx
  765.  
  766. @@:    dec    si
  767.     mov    al,ds:[si]        ; get hex digit
  768.     mov    dl,al
  769.     mov    cl,4            ; shift count
  770.     rol    dl,cl
  771.     mov    al,dl            ; save it
  772.     and    al,0fh            ; keep low nibble
  773.     daa
  774.     add    al,0f0h
  775.     adc    al,40h            ; here is the ASCII
  776.     stosb                ; save it
  777.     mov    cl,4            ; shift count
  778.     rol    dl,cl
  779.     mov    al,dl            ; save it
  780.     and    al,0fh            ; keep low nibble
  781.     daa
  782.     add    al,0f0h
  783.     adc    al,40h            ; here is the ASCII
  784.     stosb                ; save it
  785.     dec    word ptr [bp][8]    ; are we done yet?
  786.     jnz    @B
  787.     pop    bp
  788.     pop    di
  789.     pop    si
  790.     pop    dx
  791.     pop    cx
  792.     pop    ax
  793.  
  794. @Hex_str_exit:
  795.     ret
  796. Hex_String    endp
  797.  
  798.  
  799. ;-----------------------------------------------------------------------------
  800. ; This is a real down-and-dirty invalid opcode exception handler.  All this
  801. ; handler does, is take the value in DX and use it as the return address.
  802. ;-----------------------------------------------------------------------------
  803. ; Input:   DX = Return address
  804. ; Output:  None
  805. ;-----------------------------------------------------------------------------
  806. OurINT6 proc    far
  807.     pop    ax            ; get IP from stack
  808.     mov    ax,dx            ; point to return address
  809.     push    ax            ; save it
  810.     iret                ; go split
  811. OurINT6 endp
  812.  
  813. _TEXT    ENDS
  814.  
  815.  
  816.     STACK segment para public 'STACK'
  817. ;-----------------------------------------------------------------------------
  818. ; Stack segment
  819. ;-----------------------------------------------------------------------------
  820.     StackPtr    db    400h dup (?)
  821.     STACK    ends
  822.  
  823.     end    FISTBUG
  824.